using System;
using System.Data.Common;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using SeataNet.Core.Configuration;
using SeataNet.Core.Context;
using SeataNet.Core.Transaction;

namespace SeataNet.Core.XA
{
    /// <summary>
    /// XA模式服务集合扩展类
    /// </summary>
    public static class XaServiceCollectionExtensions
    {
        /// <summary>
        /// 添加XA模式服务
        /// </summary>
        /// <param name="services">服务集合</param>
        /// <param name="configureAction">配置操作</param>
        /// <returns>服务集合</returns>
        public static IServiceCollection AddXaMode(
            this IServiceCollection services, 
            Action<XaConfiguration>? configureAction = null)
        {
            if (services == null)
                throw new ArgumentNullException(nameof(services));

            // 添加XA配置
            if (configureAction != null)
            {
                services.Configure(configureAction);
            }

            // 添加XA配置选项
            services.AddOptions<XaConfiguration>()
                .Configure<IOptions<SeataConfiguration>>((xaOptions, seataOptions) =>
                {
                    // 从Seata配置中继承一些默认值
                    xaOptions.ApplicationId = seataOptions.Value.ApplicationId;
                    xaOptions.TxServiceGroup = seataOptions.Value.TxServiceGroup;
                });

            // 注册XA事务管理器
            services.TryAddScoped<IXaTransactionManager, DefaultXaTransactionManager>();

            // 注册XA事务拦截器
            services.TryAddTransient<XaTransactionInterceptor>();
            services.TryAddTransient<XaTransactionAspect>();
            services.TryAddTransient<XaTransactionTemplate>();

            // 注册XA数据源代理工厂
            services.TryAddSingleton<IXaDataSourceProxyFactory, DefaultXaDataSourceProxyFactory>();

            // 注册XA连接工厂
            services.TryAddSingleton<IXaConnectionFactory, DefaultXaConnectionFactory>();

            return services;
        }

        /// <summary>
        /// 添加XA数据源
        /// </summary>
        /// <param name="services">服务集合</param>
        /// <param name="configureAction">数据源配置操作</param>
        /// <returns>服务集合</returns>
        public static IServiceCollection AddXaDataSource(
            this IServiceCollection services,
            Action<XaDataSourceOptions> configureAction)
        {
            if (services == null)
                throw new ArgumentNullException(nameof(services));
            if (configureAction == null)
                throw new ArgumentNullException(nameof(configureAction));

            // 添加XA数据源配置
            services.Configure(configureAction);

            // 注册XA数据源
            services.TryAddSingleton<IXaDataSource, DefaultXaDataSource>();

            return services;
        }
    }

    /// <summary>
    /// XA配置类
    /// </summary>
    public class XaConfiguration
    {
        /// <summary>
        /// 应用ID
        /// </summary>
        public string ApplicationId { get; set; } = "seata-net-application";

        /// <summary>
        /// 事务服务组
        /// </summary>
        public string TxServiceGroup { get; set; } = "my_test_tx_group";

        /// <summary>
        /// 默认超时时间（毫秒）
        /// </summary>
        public int DefaultTimeout { get; set; } = 60000;

        /// <summary>
        /// 是否启用XA模式
        /// </summary>
        public bool Enabled { get; set; } = true;

        /// <summary>
        /// XA资源配置
        /// </summary>
        public XaResourceOptions Resource { get; set; } = new XaResourceOptions();

        /// <summary>
        /// XA恢复配置
        /// </summary>
        public XaRecoveryOptions Recovery { get; set; } = new XaRecoveryOptions();
    }

    /// <summary>
    /// XA资源配置
    /// </summary>
    public class XaResourceOptions
    {
        /// <summary>
        /// 是否自动注册资源
        /// </summary>
        public bool AutoRegister { get; set; } = true;

        /// <summary>
        /// 资源ID前缀
        /// </summary>
        public string ResourceIdPrefix { get; set; } = "xa-datasource-";

        /// <summary>
        /// 最大连接数
        /// </summary>
        public int MaxConnections { get; set; } = 100;

        /// <summary>
        /// 连接超时时间（毫秒）
        /// </summary>
        public int ConnectionTimeout { get; set; } = 30000;
    }

    /// <summary>
    /// XA恢复配置
    /// </summary>
    public class XaRecoveryOptions
    {
        /// <summary>
        /// 是否启用恢复
        /// </summary>
        public bool Enabled { get; set; } = true;

        /// <summary>
        /// 恢复间隔（毫秒）
        /// </summary>
        public int Interval { get; set; } = 60000;

        /// <summary>
        /// 最大重试次数
        /// </summary>
        public int MaxRetryCount { get; set; } = 5;

        /// <summary>
        /// 恢复超时时间（毫秒）
        /// </summary>
        public int Timeout { get; set; } = 300000;
    }

    /// <summary>
    /// XA数据源配置选项
    /// </summary>
    public class XaDataSourceOptions
    {
        /// <summary>
        /// 连接字符串
        /// </summary>
        public string ConnectionString { get; set; }

        /// <summary>
        /// 数据库提供程序名称
        /// </summary>
        public string ProviderName { get; set; }

        /// <summary>
        /// 资源ID
        /// </summary>
        public string ResourceId { get; set; }

        /// <summary>
        /// 是否启用连接池
        /// </summary>
        public bool EnablePooling { get; set; } = true;

        /// <summary>
        /// 最小连接池大小
        /// </summary>
        public int MinPoolSize { get; set; } = 5;

        /// <summary>
        /// 最大连接池大小
        /// </summary>
        public int MaxPoolSize { get; set; } = 100;

        /// <summary>
        /// 连接超时时间（秒）
        /// </summary>
        public int ConnectionTimeout { get; set; } = 30;

        /// <summary>
        /// 命令超时时间（秒）
        /// </summary>
        public int CommandTimeout { get; set; } = 30;
    }

    /// <summary>
    /// XA连接工厂接口
    /// </summary>
    public interface IXaConnectionFactory
    {
        /// <summary>
        /// 创建XA连接
        /// </summary>
        /// <param name="connectionString">连接字符串</param>
        /// <param name="providerName">提供程序名称</param>
        /// <returns>数据库连接</returns>
        System.Data.Common.DbConnection CreateConnection(string connectionString, string providerName);
    }

    /// <summary>
    /// 默认XA连接工厂实现
    /// </summary>
    public class DefaultXaConnectionFactory : IXaConnectionFactory
    {
        private readonly ILogger<DefaultXaConnectionFactory> _logger;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="logger">日志记录器</param>
        public DefaultXaConnectionFactory(ILogger<DefaultXaConnectionFactory> logger)
        {
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        }

        /// <summary>
        /// 创建XA连接
        /// </summary>
        /// <param name="connectionString">连接字符串</param>
        /// <param name="providerName">提供程序名称</param>
        /// <returns>数据库连接</returns>
        public System.Data.Common.DbConnection CreateConnection(string connectionString, string providerName)
        {
            if (string.IsNullOrEmpty(connectionString))
                throw new ArgumentException("连接字符串不能为空", nameof(connectionString));

            _logger.LogInformation("创建XA连接: providerName={providerName}", providerName);

            // 根据提供程序名称创建连接
            switch (providerName?.ToLower())
            {
                case "system.data.sqlclient":
                case "microsoft.data.sqlclient":
                    try
                    {
                        var sqlType = Type.GetType("Microsoft.Data.SqlClient.SqlConnection, Microsoft.Data.SqlClient")
                            ?? Type.GetType("System.Data.SqlClient.SqlConnection, System.Data");
                        if (sqlType != null)
                        {
                            return (DbConnection)Activator.CreateInstance(sqlType, connectionString);
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.LogWarning(ex, "Failed to create SQL Server connection");
                    }
                    break;

                case "mysql.data.mysqlclient":
                    try
                    {
                        var mysqlType = Type.GetType("MySql.Data.MySqlClient.MySqlConnection, MySql.Data");
                        if (mysqlType != null)
                        {
                            return (DbConnection)Activator.CreateInstance(mysqlType, connectionString);
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.LogWarning(ex, "Failed to create MySQL connection");
                    }
                    break;

                case "npgsql":
                    try
                    {
                        var npgsqlType = Type.GetType("Npgsql.NpgsqlConnection, Npgsql");
                        if (npgsqlType != null)
                        {
                            return (DbConnection)Activator.CreateInstance(npgsqlType, connectionString);
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.LogWarning(ex, "Failed to create PostgreSQL connection");
                    }
                    break;

                case "system.data.sqlite":
                case "microsoft.data.sqlite":
                    try
                    {
                        var sqliteType = Type.GetType("Microsoft.Data.Sqlite.SqliteConnection, Microsoft.Data.Sqlite")
                            ?? Type.GetType("System.Data.SQLite.SQLiteConnection, System.Data.SQLite");
                        if (sqliteType != null)
                        {
                            return (DbConnection)Activator.CreateInstance(sqliteType, connectionString);
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.LogWarning(ex, "Failed to create SQLite connection");
                    }
                    break;

                case "oracle.manageddataaccess.client":
                    try
                    {
                        var oracleType = Type.GetType("Oracle.ManagedDataAccess.Client.OracleConnection, Oracle.ManagedDataAccess");
                        if (oracleType != null)
                        {
                            return (DbConnection)Activator.CreateInstance(oracleType, connectionString);
                        }
                    }
                    catch (Exception ex)
                    {
                        _logger.LogWarning(ex, "Failed to create Oracle connection");
                    }
                    break;

                default:
                    // 尝试使用DbProviderFactory创建连接
                    if (!string.IsNullOrEmpty(providerName))
                    {
                        try
                        {
                            var factory = System.Data.Common.DbProviderFactories.GetFactory(providerName);
                            var connection = factory.CreateConnection();
                            if (connection != null)
                            {
                                connection.ConnectionString = connectionString;
                                return connection;
                            }
                        }
                        catch (Exception ex)
                        {
                            _logger.LogWarning(ex, "无法使用DbProviderFactory创建连接: providerName={providerName}", providerName);
                        }
                    }
                    break;
            }

            // If all attempts failed, throw an exception
            throw new NotSupportedException($"不支持的数据库提供程序: {providerName}");
        }
    }

    /// <summary>
    /// XA数据源接口
    /// </summary>
    public interface IXaDataSource
    {
        /// <summary>
        /// 获取XA连接
        /// </summary>
        /// <returns>XA连接</returns>
        System.Data.Common.DbConnection GetConnection();

        /// <summary>
        /// 资源ID
        /// </summary>
        string ResourceId { get; }
    }

    /// <summary>
    /// 默认XA数据源实现
    /// </summary>
    public class DefaultXaDataSource : IXaDataSource
    {
        private readonly XaDataSourceOptions _options;
        private readonly IXaConnectionFactory _connectionFactory;
        private readonly IXaDataSourceProxyFactory _dataSourceProxyFactory;
        private readonly ILogger<DefaultXaDataSource> _logger;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="options">数据源选项</param>
        /// <param name="connectionFactory">连接工厂</param>
        /// <param name="dataSourceProxyFactory">数据源代理工厂</param>
        /// <param name="logger">日志记录器</param>
        public DefaultXaDataSource(
            IOptions<XaDataSourceOptions> options,
            IXaConnectionFactory connectionFactory,
            IXaDataSourceProxyFactory dataSourceProxyFactory,
            ILogger<DefaultXaDataSource> logger)
        {
            _options = options?.Value ?? throw new ArgumentNullException(nameof(options));
            _connectionFactory = connectionFactory ?? throw new ArgumentNullException(nameof(connectionFactory));
            _dataSourceProxyFactory = dataSourceProxyFactory ?? throw new ArgumentNullException(nameof(dataSourceProxyFactory));
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        }

        /// <summary>
        /// 资源ID
        /// </summary>
        public string ResourceId => _options.ResourceId ?? $"xa-datasource-{_options.ConnectionString.GetHashCode()}";

        /// <summary>
        /// 获取XA连接
        /// </summary>
        /// <returns>XA连接</returns>
        public System.Data.Common.DbConnection GetConnection()
        {
            _logger.LogInformation("获取XA连接: resourceId={ResourceId}", ResourceId);

            // 创建原始连接
            var connection = _connectionFactory.CreateConnection(_options.ConnectionString, _options.ProviderName);

            // 检查是否有全局事务
            var xid = RootContext.GetXid();
            if (!string.IsNullOrEmpty(xid))
            {
                // 创建XA连接
                return _dataSourceProxyFactory.CreateXaConnection(connection, xid);
            }

            // 返回原始连接
            return connection;
        }
    }

    /// <summary>
    /// XA配置验证器
    /// </summary>
    public class XaConfigurationValidator : IValidateOptions<XaConfiguration>
    {
        public ValidateOptionsResult Validate(string? name, XaConfiguration options)
        {
            var result = Validate(options);
            if (!result.Success)
            {
                return ValidateOptionsResult.Fail(result.ErrorMessage ?? "验证失败");
            }
            return ValidateOptionsResult.Success;
        }

        /// <summary>
        /// 验证XA配置
        /// </summary>
        /// <param name="configuration">XA配置</param>
        /// <returns>验证结果</returns>
        public static ValidationResult Validate(XaConfiguration configuration)
        {
            if (configuration == null)
                return new ValidationResult(false, "XA配置不能为空");

            if (string.IsNullOrEmpty(configuration.ApplicationId))
                return new ValidationResult(false, "应用ID不能为空");

            if (string.IsNullOrEmpty(configuration.TxServiceGroup))
                return new ValidationResult(false, "事务服务组不能为空");

            if (configuration.DefaultTimeout <= 0)
                return new ValidationResult(false, "默认超时时间必须大于0");

            if (configuration.Resource == null)
                return new ValidationResult(false, "XA资源配置不能为空");

            if (configuration.Recovery == null)
                return new ValidationResult(false, "XA恢复配置不能为空");

            return new ValidationResult(true);
        }

        /// <summary>
        /// 验证XA数据源配置
        /// </summary>
        /// <param name="options">数据源选项</param>
        /// <returns>验证结果</returns>
        public static ValidationResult Validate(XaDataSourceOptions options)
        {
            if (options == null)
                return new ValidationResult(false, "XA数据源配置不能为空");

            if (string.IsNullOrEmpty(options.ConnectionString))
                return new ValidationResult(false, "连接字符串不能为空");

            if (options.MinPoolSize < 0)
                return new ValidationResult(false, "最小连接池大小不能小于0");

            if (options.MaxPoolSize <= 0)
                return new ValidationResult(false, "最大连接池大小必须大于0");

            if (options.MinPoolSize > options.MaxPoolSize)
                return new ValidationResult(false, "最小连接池大小不能大于最大连接池大小");

            if (options.ConnectionTimeout <= 0)
                return new ValidationResult(false, "连接超时时间必须大于0");

            if (options.CommandTimeout < 0)
                return new ValidationResult(false, "命令超时时间不能小于0");

            return new ValidationResult(true);
        }
    }

    /// <summary>
    /// 验证结果
    /// </summary>
    public class ValidationResult
    {
        /// <summary>
        /// 是否成功
        /// </summary>
        public bool Success { get; }

        /// <summary>
        /// 错误消息
        /// </summary>
        public string ErrorMessage { get; }

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="success">是否成功</param>
        /// <param name="errorMessage">错误消息</param>
        public ValidationResult(bool success, string? errorMessage = null)
        {
            Success = success;
            ErrorMessage = errorMessage;
        }
    }
}